package cn.xuchunh.guava.collection;

import com.google.common.collect.*;

import java.util.HashMap;
import java.util.Map;
import java.util.Random;

/**
 * Created on 2017/4/3.
 * <p>
 * <p><a href="http://wiki.jikexueyuan.com/project/google-guava-official-tutorial/new-collections.html">新集合类型</a></p>
 *
 * @author XCH
 */
public class GuavaCollections {

    public static void main(String[] args) {

//        multiSet();

//        multiMap();

        // 键值对的双向映射
//        biMap();

        // 使用多个键做索引
//        table();

        // RangeSet
//        rangeSet();

        // RangeMap
        rangeMap();

    }

    private static void multiSet() {
        StringBuilder sb = new StringBuilder();
        Random random = new Random();
        for (int i = 0; i < 10000; i++) {
            sb.append((char) ('a' + random.nextInt(26)) + " ");
        }
        String target = sb.toString();
        System.out.println(target);
        String[] words = target.split(" ");

        // MultiSet
        System.out.println("========HashMap========");
        long start1 = System.currentTimeMillis();
        Map<String, Integer> map = new HashMap<>();
        for (String word : words) {
            Integer count = map.get(word);
            if (count != null) {
                map.put(word, count + 1);
            } else {
                map.put(word, 1);
            }
        }
        for (Map.Entry<String, Integer> entry : map.entrySet()) {
            System.out.println(entry.getKey() + ": " + entry.getValue());
        }
        long cost1 = System.currentTimeMillis() - start1;

        System.out.println("========HashMultiSet========");
        long start2 = System.currentTimeMillis();
        Multiset<String> multiset = HashMultiset.create();
        for (String word : words) {
            multiset.add(word);
        }
        for (String word : multiset.elementSet()) {
            System.out.println(word + ": " + multiset.count(word));
        }
        System.out.println("cost1: " + cost1);
        System.out.println("cost2: " + (System.currentTimeMillis() - start2));
    }


    private static void multiMap() {
        Multimap<String, String> multimap = HashMultimap.create();
        multimap.put("a", "a");
        multimap.put("a", "b");
        multimap.put("a", "c");
        multimap.put("a", "d");
        multimap.put("a", "a");
        multimap.put("b", "a");
        multimap.put("b", "b");
        multimap.put("b", "c");
        multimap.put("b", "d");
        System.out.println("keys: " + multimap.keys());
        System.out.println("values: " + multimap.values());
        System.out.println(multimap.get("a"));
        System.out.println(multimap.get("c"));
        System.out.println("asMap: " + multimap.asMap());
        System.out.println("entries: " + multimap.entries());
        System.out.println("keySet: " + multimap.keySet());
    }

    private static void biMap() {

        //  values()返回 Set 而不是普通的 Collection

        BiMap<String, Integer> bimap = HashBiMap.create();
        bimap.put("a", 1);
        bimap.put("b", 2);
        try {
            bimap.put("a", 2);
        } catch (Exception e) {
            e.printStackTrace();
        }
        bimap.forcePut("a", 2);

        System.out.println(bimap.inverse().get(2));
        System.out.println(bimap.get("b"));
    }

    private static void table() {
        Table<String, String, Integer> table = HashBasedTable.create();
        table.put("a", "a", 1);
        table.put("a", "b", 2);
        table.put("x", "b", 13);
        table.put("x", "d", 14);
        System.out.println("rowMap: " + table.rowMap());
        System.out.println("row[a]: " + table.row("a"));
        System.out.println("columnMap: " + table.columnMap());
        System.out.println("column[b]: " + table.column("b"));
        System.out.println("cellSet: " + table.cellSet());
        System.out.println(table.get("a", "b"));
    }

    private static void rangeSet() {

        // RangeSet描述了一组不相连的、非空的区间。当把一个区间添加到可变的RangeSet时，所有相连的区间会被合并，空区间会被忽略。

        RangeSet<Integer> rangeSet = TreeRangeSet.create();
        rangeSet.add(Range.closed(1, 10)); // [1,10]
        System.out.println(rangeSet);
        rangeSet.add(Range.closedOpen(11, 15)); // [1,10], [11, 15)
        System.out.println(rangeSet);
        rangeSet.add(Range.closedOpen(15, 20)); // [1,10], [11, 20)
        System.out.println(rangeSet);
        rangeSet.add(Range.openClosed(0, 0)); // 空区间
        System.out.println(rangeSet);
        rangeSet.remove(Range.open(5, 10)); // [1, 5],[10,10],[11,20]
        System.out.println(rangeSet);

        System.out.println("complement: " + rangeSet.complement());
        System.out.println("subRangeSet: " + rangeSet.subRangeSet(Range.openClosed(14, 16)));
        System.out.println("subRangeSet: " + rangeSet.subRangeSet(Range.closed(30, 40)));
        System.out.println("subRangeSet: " + rangeSet.subRangeSet(Range.closed(14, 40)));
        System.out.println("asRanges: " + rangeSet.asRanges());

        System.out.println("contains 6: " + rangeSet.contains(6));
        System.out.println("contains 18: " + rangeSet.contains(18));
        System.out.println("rangeContaining: " + rangeSet.rangeContaining(18));
        System.out.println("rangeContaining: " + rangeSet.rangeContaining(22));

        System.out.println(rangeSet.encloses(Range.openClosed(14, 16)));
        System.out.println(rangeSet.encloses(Range.closed(30, 40)));
        System.out.println(rangeSet.encloses(Range.closed(14, 40)));

        System.out.println("min range: " + rangeSet.span());

    }

    private static void rangeMap(){
        // RangeMap 描述了”不相交的、非空的区间”到特定值的映射。和 RangeSet 不同，RangeMap 不会合并相邻的映射，即便相邻的区间映射到相同的值

        RangeMap<Integer, String> rangeMap = TreeRangeMap.create();
        rangeMap.put(Range.closed(1, 10), "foo");
        System.out.println(rangeMap);
        rangeMap.put(Range.open(3, 6), "bar");
        System.out.println(rangeMap);
        rangeMap.put(Range.open(10, 20), "foo");
        System.out.println(rangeMap);
        rangeMap.remove(Range.closed(5, 11));
        System.out.println(rangeMap);

        System.out.println("asMapOfRanges: " + rangeMap.asMapOfRanges());
        System.out.println("subRangeMap: " + rangeMap.subRangeMap(Range.closed(15,25)));
    }

}
